package com.kmxd.ams.app.arrange;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.util.ListUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.kmxd.ams.app.arrange.command.CommonQueryCmd;
import com.kmxd.ams.app.arrange.command.RetentionCmd;
import com.kmxd.ams.app.event.AmsEventPublisher;
import com.kmxd.ams.client.archive.IArchiveFieldSvc;
import com.kmxd.ams.client.archive.IArchiveTypeSvc;
import com.kmxd.ams.client.archive.dto.ArchiveFieldQueryDTO;
import com.kmxd.ams.client.archive.vo.ArchiveFieldListVO;
import com.kmxd.ams.client.arrange.IDocumentSvc;
import com.kmxd.ams.client.arrange.IVolumeSvc;
import com.kmxd.ams.client.arrange.dto.*;
import com.kmxd.ams.client.arrange.vo.UploadImportDataVO;
import com.kmxd.ams.client.arrange.vo.UploadImportVO;
import com.kmxd.ams.client.event.involume.ChangeInVolumeArchCodeEvent;
import com.kmxd.ams.client.event.log.VolumeLogEvent;
import com.kmxd.ams.client.oss.IEfileRecordSvc;
import com.kmxd.ams.client.oss.dto.EfileRecordDTO;
import com.kmxd.ams.client.oss.vo.EfileRecordVO;
import com.kmxd.ams.core.common.bo.LoginUser;
import com.kmxd.ams.core.common.constant.ArchConst;
import com.kmxd.ams.core.common.constant.Constants;
import com.kmxd.ams.core.common.constant.ErrorCode;
import com.kmxd.ams.core.common.enums.*;
import com.kmxd.ams.core.common.query.QueryGen;
import com.kmxd.ams.core.exception.BizTipException;
import com.kmxd.ams.core.exception.ParamsValidateException;
import com.kmxd.ams.core.util.*;
import com.kmxd.ams.infra.arrange.base.BaseBO;
import com.kmxd.ams.infra.arrange.entity.Document;
import com.kmxd.ams.infra.arrange.entity.Volume;
import com.kmxd.ams.infra.arrange.mapper.VolumeMapper;
import java.util.*;
import java.util.stream.Collectors;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 案卷级 服务实现类
 *
 * @author ZuoLG
 * @since 2022-07-20
 */
@Slf4j
@Service
@AllArgsConstructor
public class VolumeSvcImpl extends ServiceImpl<VolumeMapper, Volume> implements IVolumeSvc {

  private VolumeMapper volumeMapper;
  private IDocumentSvc documentSvc;
  private IArchiveFieldSvc archiveFieldSvc;
  private AmsEventPublisher amsEventPublisher;
  private IEfileRecordSvc efileRecordSvc;
  private CommonQueryCmd commonQueryCmd;
  private IArchiveTypeSvc archiveTypeSvc;
  private RetentionCmd retentionCmd;

  @Override
  public Page<Volume> selectPage(Page reqPage, Volume req) {
    if (NumberUtil.equals(req.getStatus(), Constants.TRASH_KEY)) {
      return baseMapper.selectDelByPage(reqPage, req.getTableId());
    }
    req.setStatus(NumberUtil.equals(req.getStatus(), Constants.TRASH_KEY) ? null : req.getStatus());
    QueryWrapper<Volume> wrapper = QueryGen.init(new QueryWrapper<Volume>(), req);
    buildSearchWrapper(req, wrapper);
    wrapper.orderBy(
        StrUtil.isNotBlank(req.getField()),
        "ascend".equals(req.getOrder()),
        StringUtils.camelToUnderline(req.getField()));

    commonQueryCmd.buildFieldOrderQuery(req, wrapper);
    // 设置数据过滤条件
    String dataConditionSql = QueryUtil.buildDataSql(req.getDataCondition());
    if (CharSequenceUtil.isNotBlank(dataConditionSql)) {
      wrapper.apply(dataConditionSql);
    }

    LambdaQueryWrapper<Volume> queryWrapper = wrapper.lambda();
    if (CharSequenceUtil.isNotBlank(req.getVolIds())) {
      Set<Long> volIds = IdUtil.split(req.getVolIds());
      queryWrapper.in(Volume::getId, volIds);
    }
    Page<Volume> page = volumeMapper.selectPage(reqPage, queryWrapper);
    return page;
  }

  @Override
  public List<Volume> selectList(Volume req) {
    if (ObjectUtil.isNotEmpty(req.getStatus())) {
      req.setStatus(
          NumberUtil.equals(req.getStatus(), Constants.TRASH_KEY) ? null : req.getStatus());
    }
    QueryWrapper<Volume> wrapper = QueryGen.init(new QueryWrapper<Volume>(), req);
    wrapper.orderBy(
        StrUtil.isNotBlank(req.getField()),
        "ascend".equals(req.getOrder()),
        StringUtils.camelToUnderline(req.getField()));

    commonQueryCmd.buildFieldOrderQuery(req, wrapper);
    // 设置数据过滤条件
    String dataConditionSql = QueryUtil.buildDataSql(req.getDataCondition());
    if (CharSequenceUtil.isNotBlank(dataConditionSql)) {
      wrapper.apply(dataConditionSql);
    }
    if (CharSequenceUtil.isNotBlank(req.getVolIds())) {
      Set<Long> ids = IdUtil.split(req.getVolIds());
      wrapper.lambda().in(Volume::getId, ids);
    }

    LambdaQueryWrapper<Volume> queryWrapper = wrapper.lambda();
    return volumeMapper.selectList(queryWrapper);
  }

  @Override
  public List<Volume> selectListByIds(Set<Long> ids) {
    LambdaQueryWrapper<Volume> queryWrapper = Wrappers.lambdaQuery();
    queryWrapper.in(Volume::getId, ids);
    return baseMapper.selectList(queryWrapper);
  }

  @Override
  public List<Volume> selectListByProjIds(Volume req) {
    LambdaQueryWrapper<Volume> queryWrapper = Wrappers.lambdaQuery();
    queryWrapper.in(Volume::getProjId, IdUtil.split(req.getProjIds()));
    return volumeMapper.selectList(queryWrapper);
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void add(Volume req) {
    checkData(req);
    req.setFondsId(
        ObjectUtil.isEmpty(req.getFondsId()) ? SecurityUtil.getFondsId() : req.getFondsId());
    req.setFondsCode(
        ObjectUtil.isEmpty(req.getFondsCode()) ? SecurityUtil.getFondsCode() : req.getFondsCode());
    req.setFondsName(
        ObjectUtil.isEmpty(req.getFondsName()) ? SecurityUtil.getFondsName() : req.getFondsName());
    // 设置默认值
    req.setDepartmentId(
        ObjectUtil.isNotEmpty(req.getDepartmentId())
            ? req.getDepartmentId()
            : SecurityUtil.getLoginUser().getDeptId());
    req.setDepartment(
        ObjectUtil.isNotEmpty(req.getDepartment())
            ? req.getDepartment()
            : SecurityUtil.getLoginUser().getDeptName());
    req.setDelFlag(DelFlagEnum.NO.getCode());
    //    if (StrUtil.isBlank(req.getArchCode()) || Objects.isNull(req.getVolSequence())) {
    //      req.setVolSequence(null);
    //      req.setArchCode(null);
    //    }
    req.setManageStatus(SecurityUtil.getManageStatus());
    setBandWithTotal(req);

    // 判断成文日期，计算到期时间
    if (ObjectUtil.isNotEmpty(req.getStartDate()) && ObjectUtil.isEmpty(req.getExpireYear())) {
      req.setExpireYear(
          retentionCmd.getExpireYear(req.getYear(), req.getRetentionPeriod(), req.getStartDate()));
    }
    volumeMapper.insert(req);

    summary(req);
    MDC.put(ArchConst.UPDATE_DATA + req.getId(), JSONUtil.toJsonStr(req));
  }

  /**
   * 脊背宽度统计设置
   *
   * @param req
   */
  private void setBandWithTotal(Volume req) {
    Integer fillingNum = Optional.ofNullable(req.getFillingNum()).orElse(0);
    String width = Optional.ofNullable(req.getBackWidth()).orElse("");
    Integer bandWidth = 0;
    if (ObjectUtil.contains(width, "cm")) {
      bandWidth = Integer.parseInt(width.replace("cm", "00"));
    }
    if (ObjectUtil.contains(width, "mm")) {
      bandWidth = Integer.parseInt(width.replace("mm", ""));
    }
    int bandWidthTotal = bandWidth * fillingNum;
    req.setBackWidthTotal(Double.valueOf(bandWidthTotal));
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void edit(Volume req) {
    if (Objects.nonNull(req.getId())) {
      checkData(req);
      Volume source = volumeMapper.selectById(req.getId());
      if (ObjectUtil.isEmpty(source)) {
        throw BizTipException.instance(ErrorCode.AIP_DATA_NOT_FOUND, "数据未找到");
      }
      setBandWithTotal(req);

      // 判断成文日期，计算到期时间
      if (ObjectUtil.isNotEmpty(req.getStartDate()) && ObjectUtil.isEmpty(req.getExpireYear())) {
        req.setExpireYear(
            retentionCmd.getExpireYear(
                req.getYear(), req.getRetentionPeriod(), req.getStartDate()));
      }
      volumeMapper.updateById(req);
      // 发布创建数据目录事件
      if (null == source) {
        return;
      }
      //      if (StrUtil.isBlank(req.getArchCode()) || Objects.isNull(req.getVolSequence())) {
      //        req.setVolSequence(null);
      //        req.setArchCode(null);
      //      }
      req.setFourCheckId(null);
      req.setFourCheckResult(null);
      source.setArchTypeId(req.getArchTypeId());
      source.setTableId(req.getTableId());
      // 刷新案卷下的文档案卷号
      if (Objects.nonNull(req.getArchCode())
          && ObjectUtil.notEqual(source.getArchCode(), req.getArchCode())) {
        amsEventPublisher.publishEvent(
            new ChangeInVolumeArchCodeEvent(
                ChangeInVolumeArchCodeDTO.builder()
                    .archTypeId(req.getArchTypeId())
                    .volIds(String.valueOf(req.getId()))
                    .projId(req.getProjId())
                    .tableId(req.getTableId())
                    .build()));
      }
      summary(req);
      MDC.put(ArchConst.UPDATE_DATA + req.getId(), JSONUtil.toJsonStr(req));
    } else {
      Set<Long> volIds = IdUtil.split(req.getVolIds());
      List<Volume> volumes = selectListByIds(volIds);
      if (ObjectUtil.isEmpty(volumes)) {
        return;
      }
      volumes.forEach(
          item -> {
            Volume source = ConvertUtil.toBean(item, Volume.class);
            source.setArchTypeId(req.getArchTypeId());
            source.setTableId(req.getTableId());

            BeanUtil.copyProperties(req, item, CopyOptions.create().ignoreNullValue());
            item.setArchTypeId(req.getArchTypeId());
            item.setTableId(req.getTableId());
            // 调整分组，设置重置档号
            item.setVolSequence(null);
            item.setArchCode(null);
            // 编辑后四性检测无效
            req.setFourCheckId(null);
            req.setFourCheckResult(null);
          });
      DynamicTableNameUtil.setTableName(req.getTableId());
      updateBatchById(volumes);
      amsEventPublisher.publishEvent(
          new ChangeInVolumeArchCodeEvent(
              ChangeInVolumeArchCodeDTO.builder()
                  .archTypeId(req.getArchTypeId())
                  .volIds(req.getVolIds())
                  .projId(req.getProjId())
                  .tableId(req.getTableId())
                  .build()));
      amsEventPublisher.publishEvent(new VolumeLogEvent(req, ArchOpEnum.BATCH_UPDATE, "批量修改"));
    }
  }

  @Override
  public void summary(Volume req) {
  }

  public void checkData(Volume req) {
    if (ObjectUtil.isNull(req.getStatus())) {
      throw BizTipException.instance(ErrorCode.ARRANGE_STATUS_CAN_NOT_NULL, "档案状态不能为空");
    }
    if (!ImmutableSet.of(ArchStatusEnum.S0.getCode(), ArchStatusEnum.S1.getCode())
        .contains(req.getStatus())) {
      return;
    }
    ArchiveFieldQueryDTO qry = new ArchiveFieldQueryDTO();
    qry.setTableId(req.getTableId());
    if (ArchStatusEnum.S0.getCode().equals(req.getStatus())) {
      qry.setAttrRepeatWarn(Boolean.TRUE);
    }
    if (ArchStatusEnum.S1.getCode().equals(req.getStatus())) {
      qry.setAttrRepeatWarnArrange(Boolean.TRUE);
    }
    List<ArchiveFieldListVO> fieldList = archiveFieldSvc.selectList(qry);
    if (ObjectUtil.isEmpty(fieldList)) {
      return;
    }
    fieldList.forEach(
        item -> {
          QueryWrapper<Volume> query = Wrappers.query();
          query
              .lambda()
              .eq(Volume::getStatus, req.getStatus())
              .ne(Objects.nonNull(req.getId()), Volume::getId, req.getId());
          query.eq(
              item.getDbFieldKey(),
              JSONUtil.parseObj(req).get(StringUtils.underlineToCamel(item.getDbFieldKey())));
          Long count = volumeMapper.selectCount(query);
          long flag = null == count ? 0 : count;
          if (flag > 0) {
            throw ParamsValidateException.instance(
                StringUtils.camelToUnderline(item.getDbFieldKey()), ParamsValidateType.DATA_REPEAT);
          }
        });
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void remove(DetachDTO req) {
    Set<Long> idList = IdUtil.split(req.getVolIds());
    // 设置盒下的文件未未装盒
    DetachDTO detachDTO = BeanUtil.copyProperties(req, DetachDTO.class);
    detachDTO.setType(DetachEnum.VOLUME.getType());
    // 根据删除案卷id，获取文件
    BaseBO baseBO = new BaseBO();
    baseBO.setVolIds(req.getVolIds());
    baseBO.setTableId(req.getDocTableId());
    List<Document> documents = documentSvc.selectListByVolIds(baseBO, true);
    if (!documents.isEmpty()) {
      Document reqDoc = new Document();
      reqDoc.setArchTypeId(req.getArchTypeId());
      reqDoc.setTableId(req.getDocTableId());
      List<String> docIds =
          documents.stream().map(item -> item.getId().toString()).collect(Collectors.toList());
      reqDoc.setDocIds(String.join(",", docIds));
      documentSvc.remove(reqDoc);
    }

    DynamicTableNameUtil.setTableName(req.getTableId());
    idList.forEach(
        item -> {
          Volume source = volumeMapper.selectById(item);
          volumeMapper.deleteById(item);
          if (null == source) {
            return;
          }
          source.setArchTypeId(req.getArchTypeId());
          source.setTableId(req.getTableId());
        });
    Volume volume = new Volume();
    volume.setTableId(req.getTableId());
    volume.setVolIds(req.getVolIds());
    amsEventPublisher.publishEvent(new VolumeLogEvent(volume, ArchOpEnum.DELETE, "删除数据到回收站"));
  }

  @Override
  public Volume view(Volume req) {
    return volumeMapper.selectById(req.getId());
  }

  @Override
  public long count(Volume req) {
    QueryWrapper<Volume> query = Wrappers.query();
    QueryGen.init(query, req);
    buildSearchWrapper(req, query);
    Long count = volumeMapper.selectCount(query);
    return null == count ? 0 : count;
  }

  private void buildSearchWrapper(Volume req, QueryWrapper<Volume> query) {
    if (StrUtil.isBlank(req.getKeywords())) {
      return;
    }
    ArchiveFieldQueryDTO qryField = new ArchiveFieldQueryDTO();
    qryField.setArchTypeId(req.getArchTypeId());
    qryField.setTableId(req.getTableId());
    qryField.setEsIndex(true);

    List<ArchiveFieldListVO> fieldList = archiveFieldSvc.selectList(qryField);
    // 过滤的list为空，会报空指针异常
    List<String> fields =
        fieldList.stream().map(ArchiveFieldListVO::getDbFieldKey).collect(Collectors.toList());
    QueryUtil.buildSearchWrapper(req.getKeywords(), fields, query);
  }

  @Override
  public void copy(VolumeCopyDTO req) {
  }

  @Override
  public void summary(VolumeSummaryDTO req) {
  }

  @Override
  public void changeStatus(VolumeChangeStatusDTO req) {
  }

  @Override
  public String getSequence(Map<String, Object> columnMap, String tableId, boolean onlyArchived) {
    QueryWrapper<Volume> queryWrapper = Wrappers.query();
    columnMap.entrySet().stream()
        .filter(
            item ->
                !ImmutableSet.of(
                        ArchConst.VOL_IDS,
                        ArchConst.VOL_ID,
                        ArchConst.ARCH_TYPE_ID,
                        ArchConst.TABLE_ID)
                    .contains(item.getKey()))
        .forEach(
            entry ->
                queryWrapper.eq(
                    StringUtils.isCamel(entry.getKey())
                        ? StringUtils.camelToUnderline(entry.getKey())
                        : entry.getKey(),
                    entry.getValue()));
    Integer sequence = null;
    queryWrapper.orderByDesc(ArchConst.VOL_SEQUENCE_DB);
    queryWrapper.last("LIMIT 0, 1");
    if (onlyArchived) {
      queryWrapper.eq(ArchConst.DEF_STATUS, ArchStatusEnum.S1.getCode());
    } else {
      queryWrapper.in(
          ArchConst.DEF_STATUS,
          ImmutableSet.of(ArchStatusEnum.S0.getCode(), ArchStatusEnum.S1.getCode()));
    }
    Object volIds = columnMap.get(ArchConst.VOL_IDS);
    if (Objects.nonNull(volIds)) {
      Set<Long> ids = IdUtil.split(String.valueOf(Optional.ofNullable(volIds).orElse("")));
      if (ObjectUtil.isNotEmpty(ids)) {
        queryWrapper.notIn(ArchConst.DEF_ID, ids);
      }
    }

    Object volId = columnMap.get(ArchConst.VOL_ID);
    if (Objects.nonNull(volId)) {
      Set<Long> ids = IdUtil.split(String.valueOf(Optional.ofNullable(volId).orElse("")));
      if (ObjectUtil.isNotEmpty(ids)) {
        queryWrapper.notIn(ArchConst.DEF_ID, ids);
      }
    }
    List<Volume> volumeList = volumeMapper.selectListNoDataScope(queryWrapper);
    if (!volumeList.isEmpty()) {
      sequence =
          Optional.ofNullable(volumeList.get(0).getVolSequence())
              .orElse(volumeList.get(0).getVolSequence());
    }
    return NumberUtil.toStr(sequence, "0");
  }

  @Override
  public Boolean cleanTrash(OptVolumeDTO req) {
    String volTableId = req.getTableId();
    Set<Long> ids = IdUtil.split(req.getVolIds());
    // 清空文件
    BaseBO baseBO = new BaseBO();
    baseBO.setArchTypeId(req.getArchTypeId());
    baseBO.setVolIds(req.getVolIds());
    baseBO.setTableId(req.getDocTableId());
    Page page = new Page(1, 1000);
    Document pageQuery = new Document();
    pageQuery.setTableId(req.getDocTableId());
    pageQuery.setStatus(Constants.TRASH_KEY);
    pageQuery.setVolIds(req.getVolIds());
    Page<Document> documents = documentSvc.selectPage(page, pageQuery);
    if (!documents.getRecords().isEmpty()) {
      List<String> docIds =
          documents.getRecords().stream()
              .map(item -> item.getId().toString())
              .collect(Collectors.toList());
      baseBO.setDocIds(String.join(",", docIds));
      documentSvc.cleanTrash(baseBO);
    }
    // 清空卷
    DynamicTableNameUtil.setTableName(volTableId);
    this.baseMapper.deletion(volTableId, ids);
    return true;
  }

  @Override
  public Boolean recoveryData(OptVolumeDTO req) {
    Set<Long> ids = IdUtil.split(req.getVolIds());
    this.baseMapper.recoveryData(req.getTableId(), ids);
    // 还原案卷下文件
    BaseBO baseBO = new BaseBO();
    baseBO.setArchTypeId(req.getArchTypeId());
    baseBO.setVolIds(req.getVolIds());
    baseBO.setTableId(req.getDocTableId());
    Page page = new Page(1, 1000);
    Document pageQuery = new Document();
    pageQuery.setTableId(req.getDocTableId());
    pageQuery.setStatus(Constants.TRASH_KEY);
    pageQuery.setVolIds(req.getVolIds());
    Page<Document> documents = documentSvc.selectPage(page, pageQuery);
    if (!documents.getRecords().isEmpty()) {
      List<String> docIds =
          documents.getRecords().stream()
              .map(item -> item.getId().toString())
              .collect(Collectors.toList());
      baseBO.setDocIds(String.join(",", docIds));
      documentSvc.recoveryData(baseBO);
    }
    amsEventPublisher.publishEvent(
        new VolumeLogEvent(
            ConvertUtil.toBean(req, Volume.class), ArchOpEnum.TURN_NOT_ARCHIVE, "从回收站恢复数据到收集库"));
    return null;
  }

  @Override
  public List<Map<String, Object>> selectExport(DataExportDTO req) {
    req.setStatus(
        ObjectUtil.isNotEmpty(req.getStatus())
                && NumberUtil.equals(req.getStatus(), Constants.TRASH_KEY)
            ? null
            : req.getStatus());
    QueryWrapper<Volume> wrapper = QueryGen.init(new QueryWrapper<Volume>(), req);
    wrapper.orderBy(
        StrUtil.isNotBlank(req.getField()), "ascend".equals(req.getOrder()), req.getField());

    String[] fields =
        req.getFields().stream()
            .filter(item -> ObjectUtil.isNotEmpty(item.getDbFieldKey()))
            .map(DocFieldDTO::getDbFieldKey)
            .toArray(String[]::new);
    wrapper.select(fields);
    LambdaQueryWrapper<Volume> queryWrapper = wrapper.lambda();
    Set<Long> ids = IdUtil.split(req.getVolIds());
    if (ObjectUtil.isNotEmpty(ids)) {
      queryWrapper.in(Volume::getId, ids);
    }
    return volumeMapper.selectMaps(queryWrapper);
  }

  @Override
  public UploadImportVO importUpload(UploadImportFileDTO req) throws Exception {
    UploadImportVO archUploadVO = new UploadImportVO();
    EfileRecordDTO recordDTO = new EfileRecordDTO();
    recordDTO.setArchTypeId(req.getArchTypeId());
    EfileRecordVO efileRecordVO = efileRecordSvc.uploadTemp(req.getFile(), recordDTO);
    archUploadVO.setFileInfo(efileRecordVO);
    // 查询数据库表头
    ArchiveFieldQueryDTO queryDTO = BeanUtil.copyProperties(req, ArchiveFieldQueryDTO.class);
    List<ArchiveFieldListVO> fields = archiveFieldSvc.selectList(queryDTO);
    List<String> header =
        fields.stream().map(item -> item.getDbFieldName()).collect(Collectors.toList());
    // 读取excel表头,匹配Excel表头
    EasyExcel.read(
            efileRecordVO.getFile(),
            new AnalysisEventListener<Map<Integer, String>>() {
              // 直接使用Map来保存数据
              @Override
              public void invoke(Map<Integer, String> rowData, AnalysisContext context) {}

              @Override
              public void doAfterAllAnalysed(AnalysisContext context) {
                // 所有行都解析完成
                archUploadVO.setTotalCount(context.getTotalCount());
              }

              @Override
              public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
                log.info("表头数据 excelHead= {}", headMap);
                List<String> fieldHead = headMap.values().stream().collect(Collectors.toList());
                archUploadVO.setHeadExcel(fieldHead);
              }
            })
        .sheet()
        .doRead();
    List<String> newFields =
        CollectionUtil.intersection(header, archUploadVO.getHeadExcel()).stream()
            .collect(Collectors.toList());
    archUploadVO.setFields(newFields);
    return archUploadVO;
  }

  @Override
  public UploadImportDataVO importData(UploadImportDataDTO req) throws Exception {
    UploadImportDataVO dataVO = new UploadImportDataVO();
    try {
      if (StrUtil.isBlank(req.getTableId())) {
        throw BizTipException.instance(
            ErrorCode.ARCHIVE_DATA_EXIST, StrUtil.format("请确定导入档案库，必须参数tableId为空!"));
      }
      // 根据导入的字段进行导入处理,查询数据库表头
      ArchiveFieldQueryDTO queryDTO = BeanUtil.copyProperties(req, ArchiveFieldQueryDTO.class);
      List<ArchiveFieldListVO> fields = archiveFieldSvc.selectList(queryDTO);
      // 过滤掉多余的数据
      if (!FileUtil.exist(req.getPath())) {
        throw BizTipException.instance(ErrorCode.ARCHIVE_DATA_EXIST, StrUtil.format("当前上传文件!"));
      }

      List<ArchiveFieldListVO> finalFields =
          fields.stream()
              .filter(x -> req.getFields().contains(x.getDbFieldName()))
              .collect(Collectors.toList());

      Long fondsId = SecurityUtil.getFondsId();
      String fondsName = SecurityUtil.getFondsName();
      LoginUser loginUser = SecurityUtil.getLoginUser();
      Long manageStatus = SecurityUtil.getManageStatus();
      // 读取Excel信息
      EasyExcel.read(
              req.getPath(),
              new ReadListener<Map<Integer, String>>() {
                Map<Integer, ReadCellData<?>> headMaps;
                /** 临时存储 */
                private List<Map<String, Object>> cachedDataList =
                    ListUtils.newArrayListWithExpectedSize(Constants.DEF_BATCH_SAVE_SIZE * 2);

                @Override
                public void invoke(Map<Integer, String> rowData, AnalysisContext context) {
                  // 读取到的每行数据,其key是以0开始的索引
                  Map<String, Object> rowMap = MapUtil.newHashMap();
                  rowData.forEach(
                      (key, value) -> {
                        ReadCellData cellData = MapUtil.get(headMaps, key, ReadCellData.class);
                        String cnKey =
                            ObjectUtil.isNotEmpty(cellData) ? cellData.getStringValue() : null;
                        if (req.getFields().contains(cnKey)) {
                          rowMap.put(getKeyEn(cnKey, finalFields), value);
                        }
                      });
                  cachedDataList.add(rowMap);
                  if (cachedDataList.size() >= Constants.DEF_BATCH_SAVE_SIZE * 2) {
                    List<Map<String, Object>> tmpList =
                        org.apache.commons.compress.utils.Lists.newArrayList();
                    tmpList.addAll(cachedDataList);
                    if (ObjectUtil.equal(req.getUpdateArchCode(), 1)) {
                      saveDataDb(req, tmpList, fields, fondsId, fondsName, loginUser, manageStatus);
                      dataVO.setSuccessTotal(dataVO.getSuccessTotal() + cachedDataList.size());
                    } else {
                      saveDataDbAdd(
                          req, tmpList, fields, fondsId, fondsName, loginUser, manageStatus);
                      dataVO.setSuccessTotal(dataVO.getSuccessTotal() + cachedDataList.size());
                    }
                    // 存储完成清理 list
                    cachedDataList =
                        ListUtils.newArrayListWithExpectedSize(Constants.DEF_BATCH_SAVE_SIZE * 2);
                  }
                }

                @Override
                public void invokeHead(
                    Map<Integer, ReadCellData<?>> headMap, AnalysisContext context) {
                  headMaps = headMap;
                }

                @Override
                public void doAfterAllAnalysed(AnalysisContext context) {
                  List<Map<String, Object>> tmpList =
                      org.apache.commons.compress.utils.Lists.newArrayList();
                  tmpList.addAll(cachedDataList);
                  if (ObjectUtil.equal(req.getUpdateArchCode(), 1)) {
                    saveDataDb(req, tmpList, fields, fondsId, fondsName, loginUser, manageStatus);
                    dataVO.setSuccessTotal(dataVO.getSuccessTotal() + cachedDataList.size());
                  } else {
                    saveDataDbAdd(
                        req, tmpList, fields, fondsId, fondsName, loginUser, manageStatus);
                    dataVO.setSuccessTotal(dataVO.getSuccessTotal() + cachedDataList.size());
                  }
                }
              })
          .sheet()
          .doRead();

      try {
        FileUtil.del(req.getPath());
      } catch (Exception e) {
        log.debug("删除临时文件异常:{}", e.getMessage());
      }
    } catch (Exception ex) {
      ex.printStackTrace();
      throw BizTipException.instance(
          ErrorCode.ARCHIVE_DATA_EXIST, StrUtil.format("数据导入异常，异常信息：{}!", ex.getMessage()));
    }

    return dataVO;
  }

  @Async
  protected void saveDataDbAdd(
      UploadImportDataDTO req,
      List<Map<String, Object>> datas,
      List<ArchiveFieldListVO> fields,
      Long fondsId,
      String fondsName,
      LoginUser loginUser,
      Long manageStatus) {
    try {
      // 执行数据转换为entity
      List<Volume> volumeList =
          datas.stream()
              .map(
                  item -> {
                    Volume volume = BeanUtil.copyProperties(item, Volume.class);
                    volume.setArchTypeId(req.getArchTypeId());
                    volume.setTableId(req.getTableId());
                    volume.setFondsId(fondsId);
                    volume.setDepartmentId(loginUser.getDeptId());
                    volume.setDepartment(loginUser.getDeptName());
                    if (ObjectUtil.isNotEmpty(req.getProjId())) {
                      volume.setProjId(req.getProjId());
                      volume.setProjCode(req.getProjCode());
                    }
                    if (ObjectUtil.isNotEmpty(req.getVolId())) {
                      volume.setVolId(req.getVolId());
                    }
                    if (ObjectUtil.equals(req.getDefFondsCode(), 1)) {
                      volume.setFondsId(fondsId);
                      volume.setFondsName(fondsName);
                    }
                    return volume;
                  })
              .collect(Collectors.toList());
      // 获取所有导出的档号
      List<String> archCodes =
          volumeList.stream().map(Volume::getArchCode).collect(Collectors.toList());
      // 查询库里有次档号的数据
      DynamicTableNameUtil.setTableName(req.getTableId());
      LambdaQueryWrapper<Volume> queryWrapper = Wrappers.lambdaQuery();
      queryWrapper.in(Volume::getArchCode, archCodes);
      List<Volume> volDbList = Lists.newArrayList();
      if (archCodes.size() != 0) {
        volDbList = volumeMapper.selectList(queryWrapper);
      }
      // 执行数据转换为entity
      List<Volume> finalDocDbList = volDbList;
      volumeList =
          volumeList.stream()
              .map(
                  item -> {
                    Volume volume = BeanUtil.copyProperties(item, Volume.class);
                    volume.setManageStatus(manageStatus);
                    volume.setArchTypeId(req.getArchTypeId());
                    volume.setTableId(req.getTableId());
                    List<Volume> idObj =
                        finalDocDbList.stream()
                            .filter(vol -> vol.getArchCode().equalsIgnoreCase(item.getArchCode()))
                            .collect(Collectors.toList());
                    if (!idObj.isEmpty()) {
                      volume.setId(idObj.get(0).getId());
                    }
                    return volume;
                  })
              .collect(Collectors.toList());

      // 执行数据添加功能
      this.saveBatch(volumeList);
    } finally {
      try {
        FileUtil.del(req.getPath());
      } catch (IORuntimeException e) {
        log.error("案卷导入异常:{}", e.getMessage());
      }
    }
  }

  @Async
  protected void saveDataDb(
      UploadImportDataDTO req,
      List<Map<String, Object>> datas,
      List<ArchiveFieldListVO> fields,
      Long fondsId,
      String fondsName,
      LoginUser loginUser,
      Long manageStatus) {
    try {
      // 执行数据转换为entity
      List<Volume> volumeList =
          datas.stream()
              .map(
                  item -> {
                    Volume volume = BeanUtil.copyProperties(item, Volume.class);
                    volume.setArchTypeId(req.getArchTypeId());
                    volume.setTableId(req.getTableId());
                    volume.setFondsId(fondsId);
                    volume.setDepartmentId(loginUser.getDeptId());
                    volume.setDepartment(loginUser.getDeptName());
                    volume.setManageStatus(manageStatus);
                    if (ObjectUtil.isNotEmpty(req.getProjId())) {
                      volume.setProjId(req.getProjId());
                      volume.setProjCode(req.getProjCode());
                    }
                    if (ObjectUtil.isNotEmpty(req.getVolId())) {
                      volume.setVolId(req.getVolId());
                    }
                    if (ObjectUtil.equals(req.getDefFondsCode(), 1)) {
                      volume.setFondsId(fondsId);
                      volume.setFondsName(fondsName);
                    }
                    return volume;
                  })
              .collect(Collectors.toList());
      // 获取所有导出的档号
      List<String> archCodes =
          volumeList.stream().map(Volume::getArchCode).collect(Collectors.toList());
      // 查询库里有次档号的数据
      DynamicTableNameUtil.setTableName(req.getTableId());
      LambdaQueryWrapper<Volume> queryWrapper = Wrappers.lambdaQuery();
      queryWrapper.in(Volume::getArchCode, archCodes);
      List<Volume> volDbList = Lists.newArrayList();
      if (archCodes.size() != 0) {
        volDbList = volumeMapper.selectList(queryWrapper);
      }
      // 执行数据转换为entity
      List<Volume> finalDocDbList = volDbList;
      volumeList =
          volumeList.stream()
              .map(
                  item -> {
                    Volume volume = BeanUtil.copyProperties(item, Volume.class);
                    volume.setManageStatus(manageStatus);
                    volume.setArchTypeId(req.getArchTypeId());
                    volume.setTableId(req.getTableId());
                    List<Volume> idObj =
                        finalDocDbList.stream()
                            .filter(vol -> vol.getArchCode().equalsIgnoreCase(item.getArchCode()))
                            .collect(Collectors.toList());
                    if (!idObj.isEmpty()) {
                      volume.setId(idObj.get(0).getId());
                    }
                    return volume;
                  })
              .collect(Collectors.toList());

      // 执行数据添加功能
      this.saveOrUpdateBatch(volumeList);
    } finally {
      try {
        FileUtil.del(req.getPath());
      } catch (IORuntimeException e) {
        log.error("案卷导入异常:{}", e.getMessage());
      }
    }
  }

  private String getKeyEn(String keyCn, List<ArchiveFieldListVO> fields) {
    List<ArchiveFieldListVO> field =
        fields.stream()
            .filter(item -> item.getDbFieldName().equalsIgnoreCase(keyCn))
            .collect(Collectors.toList());
    return field.size() > 0 ? StringUtils.underlineToCamel(field.get(0).getDbFieldKey()) : keyCn;
  }

  @Override
  public List<Volume> selectListIgnoreFonds(BaseBO req) {
    return this.baseMapper.selectListIgnoreFonds(req.getTableId(), req.getVolIds());
  }
}
